Skip to content

- Fix data race in GlobalConfig#13

Merged
ezhk merged 1 commit intomainfrom
refact
Apr 30, 2026
Merged

- Fix data race in GlobalConfig#13
ezhk merged 1 commit intomainfrom
refact

Conversation

@borislitv
Copy link
Copy Markdown
Collaborator

  • Add 26 unit + 4 integration tests (87.6% coverage)
  • Add GitHub Actions CI/CD for tests and Helm OCI publishing
  • Add GitHub Actions CI/CD for docker images build and publishing
  • Deployment builder
  • Add Kubernetes Events for auditing
  • Add Status Conditions (Ready, Synced, Progressing)
  • Add Finalizer for graceful cleanup
  • Add automatic Yanet deletion when worker node deleted
  • Add validation webhook
  • Add prom metrics
  • Convert all logging to structured format (key-value pairs)
  • Sync Helm chart with internal (v0.1.5)
  • Add comprehensive documentation

@borislitv borislitv force-pushed the refact branch 11 times, most recently from af96843 to e27fa44 Compare April 29, 2026 17:29
@github-actions
Copy link
Copy Markdown

🤖 AI Code Review

Changed files: api/v1alpha1/yanet_webhook.go,api/v1alpha1/yanet_webhook_test.go,api/v1alpha1/yanetconfig_webhook.go,api/v1alpha1/yanetconfig_webhook_test.go,internal/controller/metrics.go,internal/controller/node_deletion.go,internal/controller/node_deletion_test.go,internal/controller/yanet_conditions.go,internal/controller/yanet_conditions_test.go,internal/controller/yanet_controller_integration_test.go,internal/controller/yanet_reconciler_test.go,internal/helpers/helpers_test.go,internal/helpers/http_getters_test.go,internal/manifests/announcer_test.go,internal/manifests/bird_test.go,internal/manifests/builder.go,internal/manifests/controlplane_test.go,internal/manifests/dataplane_test.go,internal/manifests/helpers_test.go,api/v1alpha1/yanet_types.go,api/v1alpha1/yanetconfig_types.go,api/v1alpha1/zz_generated.deepcopy.go,cmd/main.go,internal/controller/node_reconciler.go,internal/controller/suite_test.go,internal/controller/yanet_controller.go,internal/controller/yanet_reconciler.go,internal/controller/yanetconfig_controller.go,internal/helpers/helpers.go,internal/manifests/announcer.go,internal/manifests/bird.go,internal/manifests/controlplane.go,internal/manifests/dataplane.go,internal/manifests/helpers.go

This automated review checks for:

  • 🔒 Race conditions and concurrency issues
  • 🔗 Potential deadlocks
  • ⚠️ Error handling patterns
  • 🚀 Goroutine lifecycle management
  • 📋 Context usage
  • 🎯 Nil safety

🔍 Static Analysis Results

📊 Staticcheck

✅ No issues found

🔒 Security Analysis (gosec)

✅ No security issues found

🔧 Go Vet

✅ No issues found

🏁 Race Detector

✅ No race conditions detected

🚀 Concurrency Patterns Analysis

Goroutines found:

./internal/controller/suite_test.go:108:	go func() {
./internal/controller/yanet_reconciler_test.go:131:		go func(hostNum int) {
./api/v1alpha1/groupversion_info.go:31:	// SchemeBuilder is used to add go types to the GroupVersionKind scheme

Mutex usage:

./internal/controller/yanet_controller.go:43:	lock           sync.Mutex
./internal/controller/yanet_reconciler_test.go:90:				lock:           sync.Mutex{},
./internal/controller/yanet_reconciler_test.go:119:		lock:           sync.Mutex{},
./api/v1alpha1/yanetconfig_types.go:58:	Lock   sync.Mutex      `json:"-"`

Context usage:

./internal/controller/suite_test.go:59:	ctx, cancel = context.WithCancel(context.TODO())
./internal/controller/yanet_controller_integration_test.go:49:		ctx := context.Background()
./internal/controller/yanet_controller_integration_test.go:402:		ctx := context.Background()
./internal/controller/node_deletion_test.go:130:			ctx := context.Background()
./internal/manifests/dataplane_test.go:78:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:143:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:166:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:83:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:219:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:243:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:277:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/helpers_test.go:251:	ctx := context.Background()
./internal/manifests/announcer_test.go:82:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:180:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:246:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:83:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:185:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:257:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:282:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/helpers/helpers_test.go:33:	ctx := context.Background()
./internal/helpers/helpers_test.go:228:	ctx := context.Background()
./internal/helpers/helpers_test.go:398:	ctx := context.Background()
./internal/helpers/helpers_test.go:542:	ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:129:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:205:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:230:	ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:104:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:222:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:248:	ctx := context.Background()

Defer patterns:

./internal/controller/yanet_reconciler.go:50:	defer r.lock.Unlock()
./internal/controller/yanet_reconciler_test.go:132:			defer wg.Done()

⚠️ Error Handling Patterns

Potential unchecked errors:

./internal/controller/yanet_controller_integration_test.go:425:			_, err := configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/yanet_controller_integration_test.go:444:			_, err = configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/node_deletion_test.go:131:			_, err := r.handleNodeDeletion(ctx, tt.nodeName)
./internal/helpers/http_getters_test.go:75:			_, err := HttpGet(server.URL)
./internal/helpers/http_getters_test.go:89:	_, err := HttpGet("http://invalid-host-that-does-not-exist-12345.local")
./internal/helpers/http_getters_test.go:106:	_, err := HttpGet(server.URL)
./api/v1alpha1/yanetconfig_webhook_test.go:206:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanetconfig_webhook_test.go:231:	_, err := config.ValidateDelete(ctx, config)
./api/v1alpha1/yanet_webhook_test.go:105:			_, err := tt.yanet.ValidateCreate(ctx, tt.yanet)
./api/v1alpha1/yanet_webhook_test.go:223:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanet_webhook_test.go:249:	_, err := yanet.ValidateDelete(ctx, yanet)

Nil checks:

./cmd/main.go:125:	if err != nil {
./cmd/main.go:149:	if err = (&yanetv1alpha1.Yanet{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:153:	if err = (&yanetv1alpha1.YanetConfig{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:159:	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
./cmd/main.go:163:	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
./cmd/main.go:169:	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
./internal/controller/yanet_reconciler.go:80:			if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:91:		if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:101:	if err != nil {
./internal/controller/yanet_reconciler.go:117:		if setErr := ctrl.SetControllerReference(yanet, dep, r.Scheme); setErr != nil {
./internal/controller/yanet_reconciler.go:127:		if err != nil && errors.IsNotFound(err) {
./internal/controller/yanet_reconciler.go:138:			if err != nil {
./internal/controller/yanet_reconciler.go:161:		} else if err != nil {
./internal/controller/yanet_reconciler.go:190:			if err != nil {
./internal/controller/yanet_reconciler.go:225:	if err != nil {
./internal/controller/yanet_reconciler.go:254:		if err != nil {
./internal/controller/yanetconfig_controller.go:59:	if err != nil {
./internal/controller/yanet_controller_integration_test.go:154:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:161:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:168:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:211:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:278:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:310:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:366:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:379:				if err != nil {
./internal/controller/yanet_controller.go:84:	if err != nil {
./internal/controller/yanet_controller.go:99:		if reconcileErr != nil {
./internal/controller/yanet_controller.go:111:	if err != nil {
./internal/controller/node_reconciler.go:57:	if err != nil {
./internal/controller/node_reconciler.go:72:		if err != nil {

Automated analysis using static analysis tools and pattern matching
For systematic review protocol, see .roo/rules/go-code-review.md

@github-actions
Copy link
Copy Markdown

🤖 AI Code Review

Changed files: api/v1alpha1/yanet_webhook.go,api/v1alpha1/yanet_webhook_test.go,api/v1alpha1/yanetconfig_webhook.go,api/v1alpha1/yanetconfig_webhook_test.go,internal/controller/metrics.go,internal/controller/node_deletion.go,internal/controller/node_deletion_test.go,internal/controller/yanet_conditions.go,internal/controller/yanet_conditions_test.go,internal/controller/yanet_controller_integration_test.go,internal/controller/yanet_reconciler_test.go,internal/helpers/helpers_test.go,internal/helpers/http_getters_test.go,internal/manifests/announcer_test.go,internal/manifests/bird_test.go,internal/manifests/builder.go,internal/manifests/controlplane_test.go,internal/manifests/dataplane_test.go,internal/manifests/helpers_test.go,api/v1alpha1/yanet_types.go,api/v1alpha1/yanetconfig_types.go,api/v1alpha1/zz_generated.deepcopy.go,cmd/main.go,internal/controller/node_reconciler.go,internal/controller/suite_test.go,internal/controller/yanet_controller.go,internal/controller/yanet_reconciler.go,internal/controller/yanetconfig_controller.go,internal/helpers/helpers.go,internal/manifests/announcer.go,internal/manifests/bird.go,internal/manifests/controlplane.go,internal/manifests/dataplane.go,internal/manifests/helpers.go

This automated review checks for:

  • 🔒 Race conditions and concurrency issues
  • 🔗 Potential deadlocks
  • ⚠️ Error handling patterns
  • 🚀 Goroutine lifecycle management
  • 📋 Context usage
  • 🎯 Nil safety

🔍 Static Analysis Results

📊 Staticcheck

✅ No issues found

🔒 Security Analysis (gosec)

✅ No security issues found

🔧 Go Vet

✅ No issues found

🏁 Race Detector

✅ No race conditions detected

🚀 Concurrency Patterns Analysis

Goroutines found:

./internal/controller/suite_test.go:108:	go func() {
./internal/controller/yanet_reconciler_test.go:131:		go func(hostNum int) {
./api/v1alpha1/groupversion_info.go:31:	// SchemeBuilder is used to add go types to the GroupVersionKind scheme

Mutex usage:

./internal/controller/yanet_controller.go:43:	lock           sync.Mutex
./internal/controller/yanet_reconciler_test.go:90:				lock:           sync.Mutex{},
./internal/controller/yanet_reconciler_test.go:119:		lock:           sync.Mutex{},
./api/v1alpha1/yanetconfig_types.go:58:	Lock   sync.Mutex      `json:"-"`

Context usage:

./internal/controller/suite_test.go:59:	ctx, cancel = context.WithCancel(context.TODO())
./internal/controller/yanet_controller_integration_test.go:49:		ctx := context.Background()
./internal/controller/yanet_controller_integration_test.go:402:		ctx := context.Background()
./internal/controller/node_deletion_test.go:130:			ctx := context.Background()
./internal/manifests/dataplane_test.go:78:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:143:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:166:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:83:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:219:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:243:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:277:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/helpers_test.go:251:	ctx := context.Background()
./internal/manifests/announcer_test.go:82:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:180:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:246:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:83:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:185:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:257:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:282:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/helpers/helpers_test.go:33:	ctx := context.Background()
./internal/helpers/helpers_test.go:228:	ctx := context.Background()
./internal/helpers/helpers_test.go:398:	ctx := context.Background()
./internal/helpers/helpers_test.go:542:	ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:129:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:205:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:230:	ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:104:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:222:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:248:	ctx := context.Background()

Defer patterns:

./internal/controller/yanet_reconciler.go:50:	defer r.lock.Unlock()
./internal/controller/yanet_reconciler_test.go:132:			defer wg.Done()

⚠️ Error Handling Patterns

Potential unchecked errors:

./internal/controller/yanet_controller_integration_test.go:425:			_, err := configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/yanet_controller_integration_test.go:444:			_, err = configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/node_deletion_test.go:131:			_, err := r.handleNodeDeletion(ctx, tt.nodeName)
./internal/helpers/http_getters_test.go:75:			_, err := HttpGet(server.URL)
./internal/helpers/http_getters_test.go:89:	_, err := HttpGet("http://invalid-host-that-does-not-exist-12345.local")
./internal/helpers/http_getters_test.go:106:	_, err := HttpGet(server.URL)
./api/v1alpha1/yanetconfig_webhook_test.go:206:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanetconfig_webhook_test.go:231:	_, err := config.ValidateDelete(ctx, config)
./api/v1alpha1/yanet_webhook_test.go:105:			_, err := tt.yanet.ValidateCreate(ctx, tt.yanet)
./api/v1alpha1/yanet_webhook_test.go:223:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanet_webhook_test.go:249:	_, err := yanet.ValidateDelete(ctx, yanet)

Nil checks:

./cmd/main.go:125:	if err != nil {
./cmd/main.go:149:	if err = (&yanetv1alpha1.Yanet{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:153:	if err = (&yanetv1alpha1.YanetConfig{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:159:	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
./cmd/main.go:163:	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
./cmd/main.go:169:	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
./internal/controller/yanet_reconciler.go:80:			if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:91:		if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:101:	if err != nil {
./internal/controller/yanet_reconciler.go:117:		if setErr := ctrl.SetControllerReference(yanet, dep, r.Scheme); setErr != nil {
./internal/controller/yanet_reconciler.go:127:		if err != nil && errors.IsNotFound(err) {
./internal/controller/yanet_reconciler.go:138:			if err != nil {
./internal/controller/yanet_reconciler.go:161:		} else if err != nil {
./internal/controller/yanet_reconciler.go:190:			if err != nil {
./internal/controller/yanet_reconciler.go:225:	if err != nil {
./internal/controller/yanet_reconciler.go:254:		if err != nil {
./internal/controller/yanetconfig_controller.go:59:	if err != nil {
./internal/controller/yanet_controller_integration_test.go:154:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:161:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:168:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:211:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:278:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:310:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:366:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:379:				if err != nil {
./internal/controller/yanet_controller.go:84:	if err != nil {
./internal/controller/yanet_controller.go:99:		if reconcileErr != nil {
./internal/controller/yanet_controller.go:111:	if err != nil {
./internal/controller/node_reconciler.go:57:	if err != nil {
./internal/controller/node_reconciler.go:72:		if err != nil {

Automated analysis using static analysis tools and pattern matching

@github-actions
Copy link
Copy Markdown

🤖 AI Code Review

Changed files: api/v1alpha1/yanet_webhook.go,api/v1alpha1/yanet_webhook_test.go,api/v1alpha1/yanetconfig_webhook.go,api/v1alpha1/yanetconfig_webhook_test.go,internal/controller/metrics.go,internal/controller/node_deletion.go,internal/controller/node_deletion_test.go,internal/controller/yanet_conditions.go,internal/controller/yanet_conditions_test.go,internal/controller/yanet_controller_integration_test.go,internal/controller/yanet_reconciler_test.go,internal/helpers/helpers_test.go,internal/helpers/http_getters_test.go,internal/manifests/announcer_test.go,internal/manifests/bird_test.go,internal/manifests/builder.go,internal/manifests/controlplane_test.go,internal/manifests/dataplane_test.go,internal/manifests/helpers_test.go,api/v1alpha1/yanet_types.go,api/v1alpha1/yanetconfig_types.go,api/v1alpha1/zz_generated.deepcopy.go,cmd/main.go,internal/controller/node_reconciler.go,internal/controller/suite_test.go,internal/controller/yanet_controller.go,internal/controller/yanet_reconciler.go,internal/controller/yanetconfig_controller.go,internal/helpers/helpers.go,internal/manifests/announcer.go,internal/manifests/bird.go,internal/manifests/controlplane.go,internal/manifests/dataplane.go,internal/manifests/helpers.go

This automated review checks for:

  • 🔒 Race conditions and concurrency issues
  • 🔗 Potential deadlocks
  • ⚠️ Error handling patterns
  • 🚀 Goroutine lifecycle management
  • 📋 Context usage
  • 🎯 Nil safety

🔍 Static Analysis Results

📊 Staticcheck

✅ No issues found

🔒 Security Analysis (gosec)

✅ No security issues found

🔧 Go Vet

✅ No issues found

🏁 Race Detector

✅ No race conditions detected

🚀 Concurrency Patterns Analysis

Goroutines found:

./internal/controller/suite_test.go:108:	go func() {
./internal/controller/yanet_reconciler_test.go:131:		go func(hostNum int) {
./api/v1alpha1/groupversion_info.go:31:	// SchemeBuilder is used to add go types to the GroupVersionKind scheme

Mutex usage:

./internal/controller/yanet_controller.go:43:	lock           sync.Mutex
./internal/controller/yanet_reconciler_test.go:90:				lock:           sync.Mutex{},
./internal/controller/yanet_reconciler_test.go:119:		lock:           sync.Mutex{},
./api/v1alpha1/yanetconfig_types.go:58:	Lock   sync.Mutex      `json:"-"`

Context usage:

./internal/controller/suite_test.go:59:	ctx, cancel = context.WithCancel(context.TODO())
./internal/controller/yanet_controller_integration_test.go:49:		ctx := context.Background()
./internal/controller/yanet_controller_integration_test.go:402:		ctx := context.Background()
./internal/controller/node_deletion_test.go:130:			ctx := context.Background()
./internal/manifests/dataplane_test.go:78:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:143:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:166:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:83:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:219:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:243:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:277:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/helpers_test.go:251:	ctx := context.Background()
./internal/manifests/announcer_test.go:82:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:180:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:246:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:83:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:185:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:257:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:282:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/helpers/helpers_test.go:33:	ctx := context.Background()
./internal/helpers/helpers_test.go:228:	ctx := context.Background()
./internal/helpers/helpers_test.go:398:	ctx := context.Background()
./internal/helpers/helpers_test.go:542:	ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:129:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:205:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:230:	ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:104:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:222:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:248:	ctx := context.Background()

Defer patterns:

./internal/controller/yanet_reconciler.go:50:	defer r.lock.Unlock()
./internal/controller/yanet_reconciler_test.go:132:			defer wg.Done()

⚠️ Error Handling Patterns

Potential unchecked errors:

./internal/controller/yanet_controller_integration_test.go:425:			_, err := configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/yanet_controller_integration_test.go:444:			_, err = configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/node_deletion_test.go:131:			_, err := r.handleNodeDeletion(ctx, tt.nodeName)
./internal/helpers/http_getters_test.go:75:			_, err := HttpGet(server.URL)
./internal/helpers/http_getters_test.go:89:	_, err := HttpGet("http://invalid-host-that-does-not-exist-12345.local")
./internal/helpers/http_getters_test.go:106:	_, err := HttpGet(server.URL)
./api/v1alpha1/yanetconfig_webhook_test.go:206:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanetconfig_webhook_test.go:231:	_, err := config.ValidateDelete(ctx, config)
./api/v1alpha1/yanet_webhook_test.go:105:			_, err := tt.yanet.ValidateCreate(ctx, tt.yanet)
./api/v1alpha1/yanet_webhook_test.go:223:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanet_webhook_test.go:249:	_, err := yanet.ValidateDelete(ctx, yanet)

Nil checks:

./cmd/main.go:125:	if err != nil {
./cmd/main.go:149:	if err = (&yanetv1alpha1.Yanet{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:153:	if err = (&yanetv1alpha1.YanetConfig{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:159:	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
./cmd/main.go:163:	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
./cmd/main.go:169:	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
./internal/controller/yanet_reconciler.go:80:			if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:91:		if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:101:	if err != nil {
./internal/controller/yanet_reconciler.go:117:		if setErr := ctrl.SetControllerReference(yanet, dep, r.Scheme); setErr != nil {
./internal/controller/yanet_reconciler.go:127:		if err != nil && errors.IsNotFound(err) {
./internal/controller/yanet_reconciler.go:138:			if err != nil {
./internal/controller/yanet_reconciler.go:161:		} else if err != nil {
./internal/controller/yanet_reconciler.go:190:			if err != nil {
./internal/controller/yanet_reconciler.go:225:	if err != nil {
./internal/controller/yanet_reconciler.go:254:		if err != nil {
./internal/controller/yanetconfig_controller.go:59:	if err != nil {
./internal/controller/yanet_controller_integration_test.go:154:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:161:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:168:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:211:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:278:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:310:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:366:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:379:				if err != nil {
./internal/controller/yanet_controller.go:84:	if err != nil {
./internal/controller/yanet_controller.go:99:		if reconcileErr != nil {
./internal/controller/yanet_controller.go:111:	if err != nil {
./internal/controller/node_reconciler.go:57:	if err != nil {
./internal/controller/node_reconciler.go:72:		if err != nil {

Automated analysis using static analysis tools and pattern matching

@github-actions
Copy link
Copy Markdown

🤖 AI Code Review

Changed files: api/v1alpha1/yanet_webhook.go,api/v1alpha1/yanet_webhook_test.go,api/v1alpha1/yanetconfig_webhook.go,api/v1alpha1/yanetconfig_webhook_test.go,internal/controller/metrics.go,internal/controller/node_deletion.go,internal/controller/node_deletion_test.go,internal/controller/yanet_conditions.go,internal/controller/yanet_conditions_test.go,internal/controller/yanet_controller_integration_test.go,internal/controller/yanet_reconciler_test.go,internal/helpers/helpers_test.go,internal/helpers/http_getters_test.go,internal/manifests/announcer_test.go,internal/manifests/bird_test.go,internal/manifests/builder.go,internal/manifests/controlplane_test.go,internal/manifests/dataplane_test.go,internal/manifests/helpers_test.go,api/v1alpha1/yanet_types.go,api/v1alpha1/yanetconfig_types.go,api/v1alpha1/zz_generated.deepcopy.go,cmd/main.go,internal/controller/node_reconciler.go,internal/controller/suite_test.go,internal/controller/yanet_controller.go,internal/controller/yanet_reconciler.go,internal/controller/yanetconfig_controller.go,internal/helpers/helpers.go,internal/manifests/announcer.go,internal/manifests/bird.go,internal/manifests/controlplane.go,internal/manifests/dataplane.go,internal/manifests/helpers.go

This automated review checks for:

  • 🔒 Race conditions and concurrency issues
  • 🔗 Potential deadlocks
  • ⚠️ Error handling patterns
  • 🚀 Goroutine lifecycle management
  • 📋 Context usage
  • 🎯 Nil safety

🔍 Static Analysis Results

📊 Staticcheck

✅ No issues found

🔒 Security Analysis (gosec)

✅ No security issues found

🔧 Go Vet

✅ No issues found

🏁 Race Detector

✅ No race conditions detected

🚀 Concurrency Patterns Analysis

Goroutines found:

./internal/controller/suite_test.go:108:	go func() {
./internal/controller/yanet_reconciler_test.go:131:		go func(hostNum int) {
./api/v1alpha1/groupversion_info.go:31:	// SchemeBuilder is used to add go types to the GroupVersionKind scheme

Mutex usage:

./internal/controller/yanet_controller.go:43:	lock           sync.Mutex
./internal/controller/yanet_reconciler_test.go:90:				lock:           sync.Mutex{},
./internal/controller/yanet_reconciler_test.go:119:		lock:           sync.Mutex{},
./api/v1alpha1/yanetconfig_types.go:58:	Lock   sync.Mutex      `json:"-"`

Context usage:

./internal/controller/suite_test.go:59:	ctx, cancel = context.WithCancel(context.TODO())
./internal/controller/yanet_controller_integration_test.go:49:		ctx := context.Background()
./internal/controller/yanet_controller_integration_test.go:402:		ctx := context.Background()
./internal/controller/node_deletion_test.go:130:			ctx := context.Background()
./internal/manifests/dataplane_test.go:78:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:143:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:166:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:83:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:219:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:243:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:277:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/helpers_test.go:251:	ctx := context.Background()
./internal/manifests/announcer_test.go:82:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:180:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:246:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:83:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:185:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:257:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:282:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/helpers/helpers_test.go:33:	ctx := context.Background()
./internal/helpers/helpers_test.go:228:	ctx := context.Background()
./internal/helpers/helpers_test.go:398:	ctx := context.Background()
./internal/helpers/helpers_test.go:542:	ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:129:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:205:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:230:	ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:104:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:222:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:248:	ctx := context.Background()

Defer patterns:

./internal/controller/yanet_reconciler.go:50:	defer r.lock.Unlock()
./internal/controller/yanet_reconciler_test.go:132:			defer wg.Done()

⚠️ Error Handling Patterns

Potential unchecked errors:

./internal/controller/yanet_controller_integration_test.go:425:			_, err := configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/yanet_controller_integration_test.go:444:			_, err = configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/node_deletion_test.go:131:			_, err := r.handleNodeDeletion(ctx, tt.nodeName)
./internal/helpers/http_getters_test.go:75:			_, err := HttpGet(server.URL)
./internal/helpers/http_getters_test.go:89:	_, err := HttpGet("http://invalid-host-that-does-not-exist-12345.local")
./internal/helpers/http_getters_test.go:106:	_, err := HttpGet(server.URL)
./api/v1alpha1/yanetconfig_webhook_test.go:206:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanetconfig_webhook_test.go:231:	_, err := config.ValidateDelete(ctx, config)
./api/v1alpha1/yanet_webhook_test.go:105:			_, err := tt.yanet.ValidateCreate(ctx, tt.yanet)
./api/v1alpha1/yanet_webhook_test.go:223:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanet_webhook_test.go:249:	_, err := yanet.ValidateDelete(ctx, yanet)

Nil checks:

./cmd/main.go:125:	if err != nil {
./cmd/main.go:149:	if err = (&yanetv1alpha1.Yanet{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:153:	if err = (&yanetv1alpha1.YanetConfig{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:159:	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
./cmd/main.go:163:	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
./cmd/main.go:169:	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
./internal/controller/yanet_reconciler.go:80:			if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:91:		if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:101:	if err != nil {
./internal/controller/yanet_reconciler.go:117:		if setErr := ctrl.SetControllerReference(yanet, dep, r.Scheme); setErr != nil {
./internal/controller/yanet_reconciler.go:127:		if err != nil && errors.IsNotFound(err) {
./internal/controller/yanet_reconciler.go:138:			if err != nil {
./internal/controller/yanet_reconciler.go:161:		} else if err != nil {
./internal/controller/yanet_reconciler.go:190:			if err != nil {
./internal/controller/yanet_reconciler.go:225:	if err != nil {
./internal/controller/yanet_reconciler.go:254:		if err != nil {
./internal/controller/yanetconfig_controller.go:59:	if err != nil {
./internal/controller/yanet_controller_integration_test.go:154:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:161:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:168:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:211:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:278:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:310:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:366:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:379:				if err != nil {
./internal/controller/yanet_controller.go:84:	if err != nil {
./internal/controller/yanet_controller.go:99:		if reconcileErr != nil {
./internal/controller/yanet_controller.go:111:	if err != nil {
./internal/controller/node_reconciler.go:57:	if err != nil {
./internal/controller/node_reconciler.go:72:		if err != nil {

Automated analysis using static analysis tools and pattern matching

- Add 26 unit + 4 integration tests (87.6% coverage)
- Add GitHub Actions CI/CD for tests and Helm OCI publishing
- Add GitHub Actions CI/CD for docker images build and publishing
- Add GitHub Actions for release
- Deployment builder
- Add Kubernetes Events for auditing
- Add Status Conditions (Ready, Synced, Progressing)
- Add Finalizer for graceful cleanup
- Add automatic Yanet deletion when worker node deleted
- Add validation webhook
- Add prom metrics with grafana dashboard
- Convert all logging to structured format (key-value pairs)
- Sync Helm chart with internal (v0.1.5)
- Add comprehensive documentation
@github-actions
Copy link
Copy Markdown

🤖 AI Code Review

Changed files: api/v1alpha1/yanet_webhook.go,api/v1alpha1/yanet_webhook_test.go,api/v1alpha1/yanetconfig_webhook.go,api/v1alpha1/yanetconfig_webhook_test.go,internal/controller/metrics.go,internal/controller/node_deletion.go,internal/controller/node_deletion_test.go,internal/controller/yanet_conditions.go,internal/controller/yanet_conditions_test.go,internal/controller/yanet_controller_integration_test.go,internal/controller/yanet_reconciler_test.go,internal/helpers/helpers_test.go,internal/helpers/http_getters_test.go,internal/manifests/announcer_test.go,internal/manifests/bird_test.go,internal/manifests/builder.go,internal/manifests/controlplane_test.go,internal/manifests/dataplane_test.go,internal/manifests/helpers_test.go,api/v1alpha1/yanet_types.go,api/v1alpha1/yanetconfig_types.go,api/v1alpha1/zz_generated.deepcopy.go,cmd/main.go,internal/controller/node_reconciler.go,internal/controller/suite_test.go,internal/controller/yanet_controller.go,internal/controller/yanet_reconciler.go,internal/controller/yanetconfig_controller.go,internal/helpers/helpers.go,internal/manifests/announcer.go,internal/manifests/bird.go,internal/manifests/controlplane.go,internal/manifests/dataplane.go,internal/manifests/helpers.go

This automated review checks for:

  • 🔒 Race conditions and concurrency issues
  • 🔗 Potential deadlocks
  • ⚠️ Error handling patterns
  • 🚀 Goroutine lifecycle management
  • 📋 Context usage
  • 🎯 Nil safety

🔍 Static Analysis Results

📊 Staticcheck

✅ No issues found

🔒 Security Analysis (gosec)

✅ No security issues found

🔧 Go Vet

✅ No issues found

🏁 Race Detector

✅ No race conditions detected

🚀 Concurrency Patterns Analysis

Goroutines found:

./internal/controller/suite_test.go:108:	go func() {
./internal/controller/yanet_reconciler_test.go:131:		go func(hostNum int) {
./api/v1alpha1/groupversion_info.go:31:	// SchemeBuilder is used to add go types to the GroupVersionKind scheme

Mutex usage:

./internal/controller/yanet_controller.go:43:	lock           sync.Mutex
./internal/controller/yanet_reconciler_test.go:90:				lock:           sync.Mutex{},
./internal/controller/yanet_reconciler_test.go:119:		lock:           sync.Mutex{},
./api/v1alpha1/yanetconfig_types.go:58:	Lock   sync.Mutex      `json:"-"`

Context usage:

./internal/controller/suite_test.go:59:	ctx, cancel = context.WithCancel(context.TODO())
./internal/controller/yanet_controller_integration_test.go:49:		ctx := context.Background()
./internal/controller/yanet_controller_integration_test.go:402:		ctx := context.Background()
./internal/controller/node_deletion_test.go:130:			ctx := context.Background()
./internal/manifests/dataplane_test.go:78:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:143:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/dataplane_test.go:166:	dep := DeploymentForDataplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:83:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:219:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:243:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/controlplane_test.go:277:	dep := DeploymentForControlplane(context.Background(), yanet, config, nodes)
./internal/manifests/helpers_test.go:251:	ctx := context.Background()
./internal/manifests/announcer_test.go:82:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:180:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/announcer_test.go:246:	dep := DeploymentForAnnouncer(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:83:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:185:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:257:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/manifests/bird_test.go:282:	dep := DeploymentForBird(context.Background(), yanet, config, nodes)
./internal/helpers/helpers_test.go:33:	ctx := context.Background()
./internal/helpers/helpers_test.go:228:	ctx := context.Background()
./internal/helpers/helpers_test.go:398:	ctx := context.Background()
./internal/helpers/helpers_test.go:542:	ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:129:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:205:			ctx := context.Background()
./api/v1alpha1/yanetconfig_webhook_test.go:230:	ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:104:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:222:			ctx := context.Background()
./api/v1alpha1/yanet_webhook_test.go:248:	ctx := context.Background()

Defer patterns:

./internal/controller/yanet_reconciler.go:50:	defer r.lock.Unlock()
./internal/controller/yanet_reconciler_test.go:132:			defer wg.Done()

⚠️ Error Handling Patterns

Potential unchecked errors:

./internal/controller/yanet_controller_integration_test.go:425:			_, err := configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/yanet_controller_integration_test.go:444:			_, err = configReconciler.Reconcile(ctx, reconcile.Request{
./internal/controller/node_deletion_test.go:131:			_, err := r.handleNodeDeletion(ctx, tt.nodeName)
./internal/helpers/http_getters_test.go:75:			_, err := HttpGet(server.URL)
./internal/helpers/http_getters_test.go:89:	_, err := HttpGet("http://invalid-host-that-does-not-exist-12345.local")
./internal/helpers/http_getters_test.go:106:	_, err := HttpGet(server.URL)
./api/v1alpha1/yanetconfig_webhook_test.go:206:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanetconfig_webhook_test.go:231:	_, err := config.ValidateDelete(ctx, config)
./api/v1alpha1/yanet_webhook_test.go:105:			_, err := tt.yanet.ValidateCreate(ctx, tt.yanet)
./api/v1alpha1/yanet_webhook_test.go:223:			_, err := tt.new.ValidateUpdate(ctx, tt.old, tt.new)
./api/v1alpha1/yanet_webhook_test.go:249:	_, err := yanet.ValidateDelete(ctx, yanet)

Nil checks:

./cmd/main.go:125:	if err != nil {
./cmd/main.go:149:	if err = (&yanetv1alpha1.Yanet{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:153:	if err = (&yanetv1alpha1.YanetConfig{}).SetupWebhookWithManager(mgr); err != nil {
./cmd/main.go:159:	if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
./cmd/main.go:163:	if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
./cmd/main.go:169:	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
./internal/controller/yanet_reconciler.go:80:			if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:91:		if err := r.Update(ctx, yanet); err != nil {
./internal/controller/yanet_reconciler.go:101:	if err != nil {
./internal/controller/yanet_reconciler.go:117:		if setErr := ctrl.SetControllerReference(yanet, dep, r.Scheme); setErr != nil {
./internal/controller/yanet_reconciler.go:127:		if err != nil && errors.IsNotFound(err) {
./internal/controller/yanet_reconciler.go:138:			if err != nil {
./internal/controller/yanet_reconciler.go:161:		} else if err != nil {
./internal/controller/yanet_reconciler.go:190:			if err != nil {
./internal/controller/yanet_reconciler.go:225:	if err != nil {
./internal/controller/yanet_reconciler.go:254:		if err != nil {
./internal/controller/yanetconfig_controller.go:59:	if err != nil {
./internal/controller/yanet_controller_integration_test.go:154:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:161:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:168:			if err == nil {
./internal/controller/yanet_controller_integration_test.go:211:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:278:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:310:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:366:				if err != nil {
./internal/controller/yanet_controller_integration_test.go:379:				if err != nil {
./internal/controller/yanet_controller.go:84:	if err != nil {
./internal/controller/yanet_controller.go:99:		if reconcileErr != nil {
./internal/controller/yanet_controller.go:111:	if err != nil {
./internal/controller/node_reconciler.go:57:	if err != nil {
./internal/controller/node_reconciler.go:72:		if err != nil {

Automated analysis using static analysis tools and pattern matching

@kglushen kglushen self-requested a review April 30, 2026 08:33
@kglushen
Copy link
Copy Markdown
Collaborator

LGTM

@ezhk ezhk merged commit 5ab16bf into main Apr 30, 2026
10 of 11 checks passed
@borislitv borislitv deleted the refact branch April 30, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants